package net.tavion.angelboot.common.exception;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.client.ClientException;
import lombok.extern.slf4j.Slf4j;
import net.tavion.angelboot.common.enums.SystemCode;
import net.tavion.angelboot.common.utils.ObjectMapperUtils;
import net.tavion.angelboot.common.vo.GenericResponse;
import org.apache.commons.beanutils.BeanMap;
import org.springframework.boot.web.reactive.error.DefaultErrorAttributes;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ResponseStatusException;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

@Component
@Slf4j
public class GlobalErrorAttributes extends DefaultErrorAttributes {
    @Resource
    ObjectMapper objectMapper;
    
    @Override
    public Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
//        Map<String, Object> map = super.getErrorAttributes(request, includeStackTrace);
//        map.put("exception", "SystemException");
//        map.put("message", "System Error , Check logs!");
//        map.put("status", "500");
//        map.put("error", " System Error ");
//        return map;
       return assembleError(request);
    }

    private Map<String, Object> assembleError(ServerRequest request) {

        GenericResponse genericResponse;
        Throwable error = getError(request);

        log.error(error.getMessage(),error);
        if (error instanceof ClientException || error.getCause() instanceof ClientException) {
            genericResponse=processResponseDTO(SystemCode.SYSTEM_404.getCode(),SystemCode.SYSTEM_404.getMessage());
        }else if (error instanceof ResponseStatusException || error.getCause() instanceof ResponseStatusException) {
            genericResponse=processResponseDTO(SystemCode.SYSTEM_404.getCode(),SystemCode.SYSTEM_404.getMessage());
        }else if (error instanceof AngelException || error.getCause() instanceof AngelException) {
            AngelException se=(AngelException)error;
            genericResponse =processResponseDTO(se.getErrorCode(),se.getMessage());
        }else if (error instanceof MethodArgumentNotValidException || error.getCause() instanceof MethodArgumentNotValidException) {
            genericResponse=processResponseDTO(SystemCode.ARGMENT_ERROR.getCode(),SystemCode.ARGMENT_ERROR.getMessage());
        }else if (error instanceof BindException || error.getCause() instanceof BindException) {
            genericResponse=processResponseDTO(SystemCode.BEAN_VALIDATION_ERROR.getCode(),SystemCode.BEAN_VALIDATION_ERROR.getMessage());
        } else {
            genericResponse =processResponseDTO(SystemCode.SYSTEM_CALL_ERROR.getCode(),SystemCode.SYSTEM_CALL_ERROR.getMessage());
        }

        BeanMap beanMap=new BeanMap(genericResponse);

        Map map=new HashMap();
        map.putAll(beanMap);
        map.remove("class");
        log.info("error handler response:{}", ObjectMapperUtils.writeAsString(map,objectMapper));
        return map;
    }


    private <T> GenericResponse<T> processResponseDTO(String msgCd, String msgInfo) {
        GenericResponse genericResponse=new GenericResponse();
        genericResponse.setCode(msgCd);
        genericResponse.setMessage(msgInfo);
        genericResponse.setData(new HashMap());

        return genericResponse;
    }
}
